home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
mail
/
mh
/
vmail
/
vmail.2of3
/
move.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-05
|
10KB
|
400 lines
#ifndef lint
static char *RCS_move_c = "$Id: move.c,v 1.3 91/03/08 15:57:57 jamesp Exp $";
#endif
/* --------------------
vmail -- move.c
Routines to delete or move a mail item from current folder.
Copyright (C) J. Zobel, University of Melbourne, October 1987.
-------------------- */
#include "defs.h"
#include <errno.h>
static char prevfile[LEN] = "";
extern int errno;
/* --------------------
Move current item to folder prevfile (get_name = false) or as read from
terminal (get_name = true).
-------------------- */
void
move_item(get_name)
bool get_name;
{
char *s, str[LEN], str2[LEN];
folder f, new_folder(), create_folder();
item m;
bool redraw; /* true if screen to be refreshed */
int fdi, fdo, i = FIRST-1, num, N;
/* get name if required */
if(get_name || *prevfile == '\0') {
get_string("folder? ", str);
if(*str == '\0') {
addstatus("no name given for folder", true);
return;
}
(void)strcpy(prevfile, str);
} else
(void)strcpy(str, prevfile);
/* find first page of named folder */
(void)sprintf(str2, "refiling to %s ...", str);
addstatus(str2, false);
GOTO_NAME(f, str);
if(f == (folder) NULL) { /* create folder */
f = create_folder(str);
if(f == (folder) NULL)
return;
} else {
if(f->name == curflr->name) {
addstatus("can't move item to current folder", true);
return;
}
if(f->valid) { /* goto last mail item in folder */
LAST_OF_NAME(f);
for(i=FIRST, m=f->mail ; m->next != (item) NULL ; i++, m=m->next)
;
}
}
/* remember current location of mail */
m = curmail;
num = curmail->number;
s = curflr->name;
/* delete item from current folder, update current folder & screen */
redraw = change_item(true);
if(f->valid) /* update structures of mail items */
if(i > lines) {
/* create new folder record */
f = new_folder(f);
f->mail = f->last = m;
m->prev = m->next = (item) NULL;
N = f->prev->last->number;
} else {
/* insert at end of list of mail items */
m->prev = f->last; m->next = (item) NULL;
f->last->next = m;
f->last = m;
N = m->prev->number;
}
else
N = next_vacant(f);
/* to avoid race between "send" or other process in background and vmail
foreground, compute next free slot, dont just use given value
*/
(void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
/* loop until unused file name found */
for(errno=0 ; (fdo = open(str2, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0
&& errno == EEXIST ; errno=0) {
N = N + 1;
(void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
}
if(f->valid)
m->number = N;
(void)sprintf(str, "%s/%s/%d", mail_dir, s, num);
fdi = open(str, O_RDONLY);
while((i = read(fdi, str2, LEN)) > 0) /* copy original to new */
(void)write(fdo, str2, i);
(void)close(fdi);
(void)close(fdo);
(void)unlink(str); /* remove original */
if(redraw)
display_page();
else {
add_page_header(str);
move(y, 0);
refresh();
}
addstatus("refiled", true);
if(curflr == (folder) NULL) {
to_normal();
exit(1);
}
}
/* --------------------
Delete count items.
-------------------- */
void
delete_item(count)
int count;
{
bool redraw = false;
item m;
char str[LEN];
for( ; count > 0 ; count--) {
m = curmail->next;
redraw = change_item(false);
if(redraw || m != curmail) /* on new page, or last item deleted */
break;
}
if(redraw)
display_page();
else {
add_page_header(str);
move(y, 0);
refresh();
}
}
/* --------------------
Structure for deleted item.
-------------------- */
struct {
folder flr;
int number;
} deleted = {(folder) NULL, 0};
/* --------------------
Either delete (do_move = false) or prepare to move (do_move = true) item.
Delete item from current folder, update screen, find new current folder
if current folder has become empty.
-------------------- */
bool
change_item(do_move)
bool do_move;
{
item tmp, m = curmail;
folder F, p, f = curflr, pval, nval;
char s1[LEN], s2[LEN];
bool redraw, doexit = false;
if(curmail->next == (item) NULL && curmail->prev == (item) NULL) {
/* have last item in page */
redraw = true;
pval = curflr->prev; PREV_VALID(pval);
nval = curflr->next; NEXT_VALID(nval);
if(pval == (folder) NULL && nval == (folder) NULL) {
/* no more active pages */
if(! do_move)
addstatus("Deleting last active mail item -- bye", true);
doexit = true;
} else {
/* update pages, pagenum */
for(p=curflr->prev ; p != (folder) NULL && p->name == curflr->name
; p=p->prev)
p->pages -= 1;
for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name
; p=p->next)
p->pages -= 1, p->pagenum -= 1;
/* find next active page, drop current page from list */
if(curflr->prev != (folder) NULL)
curflr->prev->next = curflr->next;
else
folders = curflr->next;
if(curflr->next != (folder) NULL)
curflr->next->prev = curflr->prev;
/*
* If the previous page is from the same folder,
* move to last item on that page. Otherwise,
* move to first page of next folder if it is
* available, else move to first page of previous
* folder if it is available.
*/
if (pval != (folder) NULL && pval->name == curflr->name) {
curflr = pval;
curmail = curflr->mail;
for ( ; curmail->next != (item) NULL; y++)
curmail = curmail->next;
}
else
{
curflr = (nval == (folder) NULL) ? pval : nval;
curmail = curflr->mail;
}
}
} else {
redraw = false;
deleteline();
/* move first item from next to current */
if(curflr->next != (folder) NULL && curflr->name == curflr->next->name)
show_title(s1, FIRST+lines-1, curflr->next->mail);
for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name ;
p=p->next) {
tmp = p->mail;
p->mail = tmp->next;
if(p->mail == (item) NULL) { /* remove folder from list */
p->prev->next = p->next;
if(p->next != (folder) NULL)
p->next->prev = p->prev;
/* update page counts */
for(F=p->prev ; F != (folder) NULL && F->name == p->name
; F=F->prev)
F->pages -= 1;
} else
p->mail->prev = (item) NULL;
p->prev->last->next = tmp;
tmp->prev = p->prev->last;
tmp->next = (item) NULL;
p->prev->last = tmp;
}
/* delete item from linked list of items */
if(m->prev == (item) NULL)
curflr->mail = m->next;
else
m->prev->next = m->next;
if(m->next == (item) NULL) {
curflr->last = m->prev;
curmail = m->prev;
y--;
} else {
m->next->prev = m->prev;
curmail = m->next;
}
move(y, 0);
}
if(! do_move) {
deleted.flr = f;
deleted.number = m->number;
(void)sprintf(s1, "%s/%s/%d", mail_dir, f->name, m->number);
(void)sprintf(s2, "%s/%s/#%d", mail_dir, f->name, m->number);
(void)rename(s1, s2);
if(doexit) {
to_normal();
exit(0);
}
}
return(redraw);
}
/* --------------------
Create folder of given name if user agrees, creating directory and
entry in linked list of folders.
-------------------- */
folder
create_folder(str)
char *str;
{
struct stat statbuf;
char str2[LEN], c;
folder fnew, p, f;
squash(str);
(void)sprintf(str2, "%s does not exist (or is empty) - create? ", str);
mvaddstr(STATUS, 0, str2); refresh();
c = getchar();
move(STATUS, 0); clrtoeol(); move(y, 0); refresh();
if(c != 'y')
return((folder) NULL);
for(p=(folder) NULL, f=folders ; f != (folder) NULL &&
strcmp(str, f->name) > 0 ; p=f, f=f->next)
;
/* create physical folder */
(void)sprintf(str2, "%s/%s", mail_dir, str);
if(stat(str2, &statbuf)) { /* doesn't exist */
if(mkdir(str2, folder_protect)) {
addstatus("Cannot make folder", true);
return((folder) NULL);
}
} else
if(!(statbuf.st_mode & S_IREAD) || !(statbuf.st_mode & S_IWRITE)
|| !(statbuf.st_mode & S_IEXEC)) {
addstatus("Cannot write in folder", true);
return((folder) NULL);
}
/* make a new folder record, insert it */
fnew = NEW(mail_folder);
fnew->name = NEWSTR(strlen(str)+1);
(void)strcpy(fnew->name, str);
fnew->mail = fnew->last = (item) NULL;
fnew->next = fnew->prev = (folder) NULL;
fnew->pages = fnew->pagenum = 1;
fnew->valid = false;
if(p == (folder) NULL) {
fnew->next = folders;
folders->prev = fnew;
folders = fnew;
} else {
p->next = fnew;
if(f != (folder) NULL)
f->prev = fnew;
fnew->prev = p;
fnew->next = f;
}
return(fnew);
}
/* --------------------
Crude undo. Sophisticated undo rather too painful to code.
-------------------- */
void
undo()
{
folder f = deleted.flr, p;
char s1[LEN], s2[LEN];
if(f == (folder) NULL) {
addstatus("nothing to undo", true);
return;
} else {
addstatus("undoing ...", true);
deleted.flr = (folder) NULL;
}
(void)sprintf(s1, "%s/%s/#%d", mail_dir, f->name, deleted.number);
(void)sprintf(s2, "%s/%s/%d", mail_dir, f->name, deleted.number);
(void)rename(s1, s2);
/* find first page of folder */
p = f; FRST_OF_NAME(p);
/* find last page of folder */
LAST_OF_NAME(f);
curflr = p;
p->next = f->next;
/* should free old folder/mail records */
/* p->valid = false; */
p->mail = p->last = (item) NULL;
p->pagenum = p->pages = 1;
if(p->next != (folder) NULL)
p->next->prev = p;
(void)find_mail(curflr, false);
curmail = curflr->mail;
y = FIRST;
display_page();
}
/* --------------------
Pack current folder. Unsets "deleted" if last removed record was
on current folder.
-------------------- */
void
pack_folder()
{
folder f = curflr;
item m;
char path[LEN], s1[LEN], s2[LEN];
bool found;
int newnum = 1;
addstatus("Packing folder ...", false);
FRST_OF_NAME(f);
/* unset undo if packing that folder */
if(deleted.flr != (folder) NULL && deleted.flr->name == curflr->name)
deleted.flr = (folder) NULL;
(void)sprintf(path, "%s/%s/", mail_dir, curflr->name);
for( ; f != (folder) NULL && f->name == curflr->name ; f=f->next)
for(m=f->mail ; m != (item) NULL ; m=m->next) {
for(found=false ; !found && newnum < m->number ; ) {
(void)sprintf(s1, "%s%d", path, newnum);
if(! access(s1, R_OK))
newnum++;
else
found = true;
}
if(found) {
(void)sprintf(s2, "%s%d", path, m->number);
(void)rename(s2, s1);
m->number = newnum;
}
}
display_page();
}